import 'dart:io';
import 'dart:math';
import 'package:flutter/services.dart';
import 'package:path/path.dart' as path;

import 'date_util.dart';
import 'entity/byte_size_format.dart';

/// @author: slc
/// 文件操作工具类
class SlcFileUtil {
  SlcFileUtil._();

  static File? getFileByPath(String filePath) {
    if (filePath.isEmpty) return null;
    return File(filePath);
  }

  static bool isFileExists(File? file) {
    if (file == null) return false;
    return file.existsSync();
  }

  static bool isFileExistsFromPath(String filePath) {
    final file = getFileByPath(filePath);
    return file != null && file.existsSync();
  }

  static bool rename(File? file, String newName) {
    if (file == null) return false;
    if (!file.existsSync()) return false;
    if (newName.isEmpty) return false;
    if (newName == path.basename(file.path)) return true;

    final newPath = path.join(path.dirname(file.path), newName);
    try {
      file.renameSync(newPath);
      return true;
    } catch (e) {
      return false;
    }
  }

  static bool isDir(String dirPath) {
    final dir = Directory(dirPath);
    return dir.existsSync() && dir.statSync().type == FileSystemEntityType.directory;
  }

  static bool isFile(String filePath) {
    final file = File(filePath);
    return file.existsSync() && file.statSync().type == FileSystemEntityType.file;
  }

  static bool createOrExistsDir(String dirPath) {
    final dir = Directory(dirPath);
    if (dir.existsSync()) return true;
    try {
      dir.createSync(recursive: true);
      return true;
    } catch (_) {
      return false;
    }
  }

  static bool createOrExistsFile(String filePath) {
    final file = File(filePath);
    if (file.existsSync()) return true;
    final dirPath = path.dirname(filePath);
    if (!createOrExistsDir(dirPath)) return false;
    try {
      file.createSync();
      return true;
    } catch (_) {
      return false;
    }
  }

  static bool copy(String srcPath, String destPath) {
    final src = File(srcPath);
    if (!src.existsSync()) return false;
    try {
      src.copySync(destPath);
      return true;
    } catch (e) {
      return false;
    }
  }

  static bool delete(String filePath) {
    final file = File(filePath);
    if (file.existsSync()) {
      try {
        file.deleteSync();
        return true;
      } catch (e) {
        return false;
      }
    }
    return false;
  }

  static bool deleteDir(String dirPath) {
    final dir = Directory(dirPath);
    if (dir.existsSync()) {
      try {
        dir.deleteSync(recursive: true);
        return true;
      } catch (e) {
        return false;
      }
    }
    return false;
  }

  static List<File> listFilesInDir(String dirPath, {bool recursive = false}) {
    final dir = Directory(dirPath);
    if (!dir.existsSync()) return [];
    return dir.listSync(recursive: recursive).whereType<File>().toList();
  }

  static DateTime? getFileLastModified(String filePath) {
    final file = File(filePath);
    if (file.existsSync()) {
      return file.lastModifiedSync();
    }
    return null;
  }

  static String getDirNameByFile(File? file) {
    if (file == null) return "";
    return getDirName(file.absolute.path);
  }

  static String getDirName(String filePath) {
    if (filePath.isEmpty) return "";

    // 規範化路徑並轉換為系統分隔符
    final normalized = path.normalize(filePath);

    // 查找最後一個分隔符位置
    final lastSep = normalized.lastIndexOf(path.separator);

    // 若找不到分隔符返回空字符串
    if (lastSep == -1) return "";

    // 截取目錄路徑 (包含結尾分隔符)
    return normalized.substring(0, lastSep + 1);
  }

  static String getFileName(String filePath) {
    return path.basename(filePath);
  }

  static String getFileNameWithoutExtension(String filePath) {
    return path.basenameWithoutExtension(filePath);
  }

  static String getFileExtension(String filePath) {
    return path.extension(filePath);
  }

  static int getFileLength(String filePath) {
    final file = File(filePath);
    if (file.existsSync()) {
      return file.lengthSync();
    }
    return 0;
  }

  static String getSize(String filePath) {
    return byte2FitMemorySize(getFileLength(filePath)).toSizeUnit();
  }

  static ByteSizeFormat byte2FitMemorySize(int byteNum) {
    if (byteNum <= 0) {
      return ByteSizeFormat(size: '0', unit: 'B', bytes: byteNum);
    }
    const units = ['B', 'KB', 'MB', 'GB', 'TB'];
    int digitGroups = (log(byteNum) / log(1024)).floor();
    digitGroups = digitGroups.clamp(0, units.length - 1);

    final size = byteNum / pow(1024, digitGroups);
    final unit = units[digitGroups];

    return ByteSizeFormat(
      size: size.toStringAsFixed(2),
      unit: unit,
      bytes: byteNum,
    );
  }


  static const String VALUE_FILE_NAME_DATE_FORMAT = "_yyyyMMdd_HHmmss";

  ///
  /// 根据时间获取文件名
  ///
  static String getFileNameByTime(
      {String? prefix,
      int? ms,
      String dateFormat = VALUE_FILE_NAME_DATE_FORMAT,
      String? suffix,
      bool carryPathSeparator = true}) {
    ms ??= DateTime.now().millisecondsSinceEpoch;
    return (carryPathSeparator ? Platform.pathSeparator : "") +
        (prefix ?? "") +
        DateUtil.formatDateMs(ms, format: dateFormat) +
        (suffix ?? "");
  }

  /// 读取文件内容
  static Future<String> readFileAsString(String filePath, {bool catchException = true}) async {
    try {
      final file = File(filePath);
      return await file.readAsString();
    } catch (e) {
      if (catchException) {
        return '';
      } else {
        rethrow;
      }
    }
  }

  /// 写入文件内容
  static Future<bool> writeFileAsString(String filePath, String content, {bool catchException = true}) async {
    try {
      final file = File(filePath);
      await file.writeAsString(content);
      return true;
    } catch (e) {
      if (catchException) {
        return false;
      } else {
        rethrow;
      }
    }
  }

  /// 追加文件内容
  static Future<bool> appendFileAsString(String filePath, String content, {bool catchException = true}) async {
    try {
      final file = File(filePath);
      await file.writeAsString(content, mode: FileMode.append);
      return true;
    } catch (e) {
      if (catchException) {
        return false;
      } else {
        rethrow;
      }
    }
  }

  /// 从 assets 读取文件内容
  static Future<String> readAssetFileAsString(String assetPath, {bool catchException = true}) async {
    try {
      return await rootBundle.loadString(assetPath);
    } catch (e) {
      if (catchException) {
        return '';
      } else {
        rethrow;
      }
    }
  }
}
